import type { Ref, ComputedRef } from 'vue';
import type { ComponentProps, FormSchema } from '../types/form';

import { unref } from 'vue';
import { cloneDeep, isBoolean, set } from 'lodash-es';

import {
  isArray,
  isFunction,
  isObject,
  isString,
  isNullOrUnDef,
  isArrayString,
  isNumber,
} from '@/utils/is';
import { defaultArrayValueComponents, defaultValueComponents, notSetItemDefaultComponents } from '../helper';
import type { ComponentType } from '../types';

export function parseFormValue(value: any, component: ComponentType, componentProps?: ComponentProps): Array<any> | undefined | null {
  let val = value

  if (isNullOrUnDef(val) && !notSetItemDefaultComponents.includes(component) && componentProps?.itemDefault) {
    val = isArray(componentProps.itemDefault) ? JSON.stringify(componentProps.itemDefault) : componentProps.itemDefault
  }

  // 兼容后台存储的表单value数据格式, 格式为 ==> "[any]"
  if (isArrayString(val)) {
    val = (JSON.parse(val) as Array<string | number | boolean>)
  }

  if (isArray(val) && !defaultArrayValueComponents.includes(component)) {
    val = val.join(',');
  }

  if (component && defaultValueComponents.includes(component)) {
    val = isNumber(val) ? val.toString() : val;
  }
  return val
}

interface UseFormValuesContext {
  defaultValueRef: Ref<any>;
  getSchema: ComputedRef<FormSchema[]>;
  formModel: Recordable;
  emit: (event: 'reset' | 'submit' | 'register' | 'update:model', ...args: any[]) => void;
}

export function useFormValues({
  defaultValueRef,
  getSchema,
  formModel,
  emit,
}: UseFormValuesContext) {

  function getIfShow(schema: FormSchema, values: Recordable) {
    const { ifShow } = schema
    let isIfShow = true;
    if (isBoolean(ifShow)) {
      isIfShow = ifShow;
    } else if (isFunction(ifShow)) {
      isIfShow = ifShow({
        field: schema.field,
        model: formModel,
        values: values,
        schema: schema,
      });
    }
    return isIfShow;
  }

  function handleFormValues(values: Recordable) {
    if (!isObject(values)) {
      return {};
    }
    const res: Recordable = {};

    for (const item of Object.entries(values)) {
      let [, value] = item;
      const [key] = item;
      const schema = getSchema.value.find((schema) => key == schema.field) as FormSchema

      const isAttachment = schema?.component === 'Attachment'

      if (isAttachment || !getIfShow(schema, values)) continue;

      if (!key || (isArray(value) && value.length === 0) || isFunction(value)) {
        continue;
      }

      if (isString(value)) {
        value = value.trim();
      }

      set(res, key, value);
    }
    return res;
  }

  function initDefault() {
    const schemas = unref(getSchema);
    const obj: Recordable = {};
    schemas.forEach((item) => {
      const { defaultValue, component, field, } = item;
      if (!isNullOrUnDef(defaultValue)) {
        let val = defaultValue;

        val = parseFormValue(val, component, item.componentProps as ComponentProps)

        obj[item.field] = val;
        formModel[item.field] = val;
      }
    });
    defaultValueRef.value = cloneDeep(obj);
  }

  return {
    handleFormValues,
    initDefault
  };
}
